libraries

library(ggplot2)
library(ggthemes)
library(gridExtra)
library(knitr)
library(htmlTable)
library(readr)
library(sp)
library(rgeos)
library(tmap)
library(tmaptools)
library(sf)
library(rgdal)
library(geojsonio)
library(spData)
library(tidyverse)
library(maptools)
library(RColorBrewer)
library(plyr)
#install.packages("reshape")
library(reshape)
library(classInt)
#install.packages("BAMMtools")
library(BAMMtools)

1 Problem

Identify locations outside the Industrial Land Designation areas with high concentration of manufacturing, other economic activities and residences.

2 Context

We have analysed 3 open data datasets refering to Manufacturing in London.

URLs:
1 https://data.london.gov.uk
2 https://www.nomisweb.co.uk/
3 https://www.ons.gov.uk/employmentandlabourmarket/peopleinwork/employmentandemployeetypes/bulletins/businessregisterandemploymentsurveybresprovisionalresults/provisionalresults2017revisedresults2016#quality-and-methodology
4 https://www.ons.gov.uk/aboutus/whatwedo/paidservices/interdepartmentalbusinessregisteridbr https://www.ons.gov.uk/businessindustryandtrade/business/activitysizeandlocation/methodologies/ukbusinessactivitysizeandlocationqmi

3 Cartographic summary

4 Analysis

A detailed analysis was carried out for the BRES dataset due to four reasons:

  1. The number of manufacturing jobs obtained from the BRES dataset is considered the best proxy to represent manufacturing intensity. This measure can be interpreted as a combination of number of manufacturing units and size.

  2. The level of detail of the BRES dataset at the LSOA area is considered sufficient to allow the selection of case study areas for micro-morphology analysis.

  3. The SIC dataset despite having a finer-grain resolution has shown innacuracies in the location of the data points (reference: Vyner street case study Cites of Making project).

  4. Despite the fact that the IDBR considers a larger sample at the national level, it is aggregated at a lower resolution geographic area (MSOA). Also, because according to a data methodological note “it is possible to get multiple business registrations at a single address and this can distort data for smaller geographical areas” (https://www.ons.gov.uk/businessindustryandtrade/business/activitysizeandlocation/methodologies/ukbusinessactivitysizeandlocationqmi/pdf).

4.1 Metadata

Data source: NOMIS official labour market statistics (ONS) URL: https://www.nomisweb.co.uk/
Definition: “An employer survey of the number of jobs held by employees broken down by full/part-time and detailed industry (5 digit SIC2007). The survey records a job at the location of an employees workplace. Available from country down to lower level super output area and Scottish datazone.”
Ref URLs: https://onsdigital.github.io/dp-classification-tools/standard-industrial-classification/ONS_SIC_hierarchy_view.html

Read NOMIS data. Lower Layer Super Output Area (2011)
Industry Standard industrial classification of economic activities (SIC) 2007 section C: Manufacturing

nom <- read_csv("/Volumes/ritd-ag-project-rd00lq-jamfe87/GIS_Analysis/dataProcessed/nomis_4835.csv") # 4,835 obs.

4.2 Data summary

Create variable ‘lsoa11_cd’ from variable ‘lsoa11_2011’ substract chr 1 to 4 (first 4 characters)

nom <- mutate(nom, lsoa11_cd = substr(lsoa_2011, 1, 9))

Summary of ‘nom’ Count and Industry percentage

summary(nom)
nrow(table(nom$Count)) # [1] 34
dCount <-as.data.frame(table(nom$Count))
colnames(dCount) <-c("Jobs", "Frequency")
dCount1 <- cbind(dCount[1:10, ], dCount[11:20, ], dCount[21:30, ], dCount[31:40, ])
htmlTable(dCount1, rnames=F, caption="Jobs count frequency per LSOA (N = 4,835)", col.columns = c("none", "#F7F7F7"), css.cell="padding-left:1em; padding-right:1em;")

Most LSOAs have 0 jobs in manufacturing. Among the rest the most frequent number is 10 jobs (in 539 LSOAs). High number of jobs ( > 1500) are an exception.

table(nom[,3]) # 22 LSOA with 20% jobs in Manufacturing Industry
nrow(table(nom$`Industry percentage`)) # [1] 107
dInd <-as.data.frame(table(nom$`Industry percentage`))
colnames(dInd) <-c("Perc.", "Frequency")
dInd1 <- cbind(dInd[1:22, ], dInd[23:44, ], dInd[45:66, ], dInd[67:88, ], dInd[89:110, ])
htmlTable(dInd1, rnames=F, caption="Jobs Percentage frequency per LSOA (N = 4,835)", col.columns = c("none", "#F7F7F7"), css.cell="padding-left:1em; padding-right:1em;")

Most LSOAs have 0% jobs in manufacturing. Among the rest the most frequent percentage is 5% (in 102 LSOAs). High percentage of jobs ( > 53%) are an exception.

4.3 Histograms

# drop 0 values
nom1 <- subset(nom, nom$Count > 0 & nom$`Industry percentage` > 0) # 1730

Summary of values > 0

summary(nom1)
# style
th <- theme_tufte(base_family = "Georgia")

h1 <- ggplot(nom1, aes(Count)) + geom_histogram(bins = 6000/5, fill="magenta") + th + ylab("LSOAs") + xlab("Jobs count")
h2 <- ggplot(nom1, aes(Count)) + geom_histogram(bins = 150/5, fill="magenta") + th + xlim(c(0, 150)) + ylab("LSOAs") + xlab("Jobs count (0-150)")
h3 <- ggplot(nom1, aes(`Industry percentage`)) + geom_histogram(bins = 100, fill="magenta") + th + ylab("LSOAs") + xlab("% of jobs in Manufacturing")
h4 <- ggplot(nom1, aes(`Industry percentage`)) + geom_histogram(bins = 200, fill="magenta") + th + xlim(c(0, 35)) + ylab("LSOAs") + xlab("% of jobs in Manufacturing (0-35%)")
grid.arrange(h1, h2, h3, h4, nrow=2)

4.4 Boxpolots

fnC <- fivenum(nom1$Count)
fnP <- fivenum(nom1$`Industry percentage`)
anC <- annotate(geom="text", label=round(fnC ,digits=2), x= 1, y=fnC, size = 3, family = "Georgia", hjust =-.2)
anP <- annotate(geom="text", label=round(fnP ,digits=2), x= 1, y=fnP, size = 3, family = "Georgia", hjust =-.2)
th <- theme(axis.title=element_blank(),axis.ticks.x = element_blank(), axis.text.x=element_blank())

bC <- ggplot(nom1, aes(1, Count)) + geom_tufteboxplot() + scale_y_log10() + theme_classic() + anC +
  ggtitle("Jobs Count (N = 1,730)") + th + theme_tufte()
bP <- ggplot(nom1, aes(1, `Industry percentage`)) + geom_tufteboxplot() + scale_y_log10() + theme_classic() + anP  + ggtitle("Jobs Percentage (N = 1,730)") + th + theme_tufte()

grid.arrange(bC, bP, nrow=1)

4.5 Maps

lsoa <- st_read("/Volumes/ritd-ag-project-rd00lq-jamfe87/GIS_Analysis/dataRaw/statistical-gis-boundaries-london/ESRI/LSOA_2011_London_gen_MHW.shp")

Create gray London basemap

Join with NOMIS data ‘nom’

mpl <- append_data(lsoa, nom, key.shp = "LSOA11CD", key.data = "lsoa11_cd", ignore.duplicates = TRUE, ignore.na = TRUE)
names(mpl)

Maps of job Counts > 40 and Percentage > 6% (> 3rd Q)

# change column name
colnames(mpl)[17] <- "IndPer"

c40 <- subset(mpl, Count >= 40) # 439 obs.
p6 <- subset(mpl, IndPer >= 6) # 434 obs.
# CP <- subset(mpl, Count >= 40 | IndPer >= 6)
mc40 <- tm_shape(gLonC) +
  tm_fill(col = "gray95") +
  tm_shape(c40) +
    tm_polygons("Count", 
        style="jenks",
        palette="PuRd",
        title= "Count",
        border.col="white",
        border.alpha = 0.1,
        legend.hist = T) +
  tm_layout(inner.margins = c(0, 0.1, 0.05, 0.2), frame = F, 
            legend.outside = T, legend.outside.position = "bottom", legend.stack = "horizontal", legend.hist.width = 3, legend.hist.height = 0.8) +
  tm_legend(main.title = "Jobs Count > 3rd Q (N=439 obs.)",
          main.title.position = "left",
          main.title.size=0.9)
mc40
mp6 <- tm_shape(gLonC) +
  tm_fill(col = "gray95") + 
  tm_shape(p6) +
    tm_polygons("IndPer", 
        style="jenks",
        palette="BuPu",
        title= "Percentage",
        border.col="white",
        border.alpha = 0.1,
        legend.hist = T) +
  tm_layout(inner.margins = c(0, 0.1, 0.05, 0.2), frame = F, 
            legend.outside = T, legend.outside.position = "bottom", legend.stack = "horizontal", legend.hist.width = 3, legend.hist.height = 0.8) +
  tm_legend(main.title = "Jobs Percentage > 3rd Q (N=434 obs.)",
          main.title.position = "left",
          main.title.size=0.9)
mp6
tmap_arrange(mc40 ,mp6 , nrow=1)

A visual comparison shows that LSOAs with high number of jobs in some cases is coincident with LSOAs with high percentage of jobs. Both meaures might be indicators of ‘manufacturing intensity’.

msum <- tm_shape(mpl) +
  tm_polygons(col="#ffffe5", border.col="#ededed", border.alpha = 0.01) + 
  tm_shape(c40) +
  tm_polygons("Count",
              style="jenks",
              palette="BuPu",
              title="Jobs Count",
              border.col="white",
              border.alpha = 0.1,
              alpha = 0.5) + 
  tm_shape(p6) +
  tm_polygons(border.col = "magenta", 
              border.alpha = 0.5, 
              alpha = 0,
              popup.vars= c("Count" ,"IndPer")) +
  tm_layout(inner.margins = c(0, 0.1, 0.05, 0.2), frame = F) 
tmap_mode("plot")
tmap mode set to plotting
msum

Interactive Map

msum.i <- msum
tmap_mode("view")
tmap mode set to interactive viewing
msum.i
tmap_save(msum.i, "msum.html")
Interactive map saved to /Users/nicolaspalominos/Documents/R_GitHub/pnum/msum.html

The selection of values with both conditions Count >= 40 & IndPer >= 6 shows 253 obs.

CP <- subset(mpl, Count >= 40 & IndPer >= 6) # 253 obs.
mCP <- tm_shape(CP) +
    tm_polygons(c("Count",
                  "IndPer"), 
        style="jenks",
        palette=list("PuRd","BuPu"),
        title=c("Count",
                "Percentage"),
        border.col="white",
        border.alpha = 0.1) +
  tm_layout(inner.margins = c(0, 0.1, 0.05, 0.2), frame = F) +
  tm_legend(legend.position = c("right", "bottom"),
          main.title = "Jobs and Percentage > 3rd Q (N=253 obs.)",
          main.title.position = "center",
          main.title.size=0.9)
mCP

4.5.1 Industrial Land 2015

ild <- st_read("/Volumes/ritd-ag-project-rd00lq-jamfe87/GIS_Analysis/dataProcessed/GLA_Ind_Land_Baseline_2015/GLA_Ind_Land_bl_2015.shp")
Reading layer `GLA_Ind_Land_bl_2015' from data source `/Volumes/ritd-ag-project-rd00lq-jamfe87/GIS_Analysis/dataProcessed/GLA_Ind_Land_Baseline_2015/GLA_Ind_Land_bl_2015.shp' using driver `ESRI Shapefile'
Simple feature collection with 104006 features and 15 fields
geometry type:  MULTIPOLYGON
dimension:      XYZ
bbox:           xmin: 503943.6 ymin: 157513.4 xmax: 561088.1 ymax: 200761.6
epsg (SRID):    NA
proj4string:    +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +datum=OSGB36 +units=m +no_defs

Summary of ‘ild’ (n=104006 obs.)

summary(ild)
    OBJECTID        OBJECTID_1       LU_CODE_20           BOROUGH          URSID      
 Min.   :     1   Min.   :  5875   Min.   : 0.000   Ealing    :10494   2045   : 1211  
 1st Qu.: 26002   1st Qu.: 39820   1st Qu.: 2.000   Hillingdon: 9114   SIL58  : 1201  
 Median : 52004   Median : 72514   Median : 5.000   Hounslow  : 8881   SIL53.3: 1200  
 Mean   : 52004   Mean   : 75011   Mean   : 6.917   Brent     : 8679   SIL99.2:  999  
 3rd Qu.: 78005   3rd Qu.:118445   3rd Qu.: 9.000   Enfield   : 6575   2096   :  960  
 Max.   :104006   Max.   :146437   Max.   :25.000   Sutton    : 4541   (Other):71563  
                                                    (Other)   :55722   NA's   :26872  
                                                 Note         LU_Code_21   TYPE_2015    GISUPDATE_  
 1                                                 : 1560   Min.   : 1.0   LSIS:20264   N/A :94299  
 Docks data unchanged from 2010 data               : 1200   1st Qu.: 2.0   NAL :45716   new :  300  
 Council Update 2015                               :  924   Median : 3.0   SIL :38026   WA  :   69  
 No update info updated sperately from 2015 exerci*:  762   Mean   : 6.1                WAWU:   90  
 Source UK Map                                     :  168   3rd Qu.: 8.0                WU  : 9248  
 (Other)                                           :  249   Max.   :24.0                            
 NA's                                              :99143                                           
    Area_Ha           Shape_Leng          Easting          Northing        Shape_Le_1      
 Min.   : 0.00000   Min.   :    0.00   Min.   :     0   Min.   :     0   Min.   :    0.00  
 1st Qu.: 0.00182   1st Qu.:   19.46   1st Qu.:517967   1st Qu.:174716   1st Qu.:   19.46  
 Median : 0.00674   Median :   45.30   Median :526235   Median :180326   Median :   45.30  
 Mean   : 0.07296   Mean   :  109.15   Mean   :525519   Mean   :179624   Mean   :  109.15  
 3rd Qu.: 0.03334   3rd Qu.:  114.88   3rd Qu.:535057   3rd Qu.:185239   3rd Qu.:  114.88  
 Max.   :81.45079   Max.   :20927.35   Max.   :561042   Max.   :200758   Max.   :20927.35  
                                                                                           
   Shape_Area                 geometry     
 Min.   :     0.0   MULTIPOLYGON Z:104006  
 1st Qu.:    18.2   epsg:NA       :     0  
 Median :    67.4   +proj=tmer... :     0  
 Mean   :   729.6                          
 3rd Qu.:   333.4                          
 Max.   :814507.9                          
                                           

Largest area is near 81 ha and 1st Qu goes from 0 to 18 sqm. (sqm to ha = divide by 10k) Frequency by type (‘TYPE_2015’)

t5 <- count(ild, vars = "TYPE_2015")
htmlTable(t5, rnames=F, caption="Industrial Land Type", col.columns = c("none", "#F7F7F7"), css.cell="padding-left:1em; padding-right:1em;")
Industrial Land Type
TYPE_2015 freq
LSIS 20264
NAL 45716
SIL 38026

Shape area summary by Type

library(purrr)
typeSUM <- ild %>% split(.$TYPE_2015) %>% map(summary)
class(ild)
[1] "sf"         "data.frame"
ilddf <- st_set_geometry(ild, NULL)
tSu <- ilddf[, c(8,15)] %>%
  group_by(TYPE_2015) %>%
  summarise_if(
    is.numeric,
    funs(mean = mean, median = median, min = min, max = max, sd = sd) 
  )
package ‘bindrcpp’ was built under R version 3.4.4
round_df <- function(x, digits) {
    # round all numeric variables
    # x: data frame 
    # digits: number of digits to round
    numeric_columns <- sapply(x, mode) == 'numeric'
    x[numeric_columns] <-  round(x[numeric_columns], digits)
    x
}
tSu <- cbind(tSu[,1], round_df(tSu[,2:5], 2))
htmlTable(tSu, rnames=F, caption="Industrial Land Type", col.columns = c("none", "#F7F7F7"), css.cell="padding-left:1em; padding-right:1em;")
Industrial Land Type
TYPE_2015 mean median min max
LSIS 570.92 86.47 0 165982.37
NAL 555.58 42.68 0 359925.45
SIL 1023.27 99.16 0 814507.91

Analyse area distributuon by type

htmlTable(tyS, caption="Industrial Land Type", col.columns = c("none", "#F7F7F7"), css.cell="padding-left:1em; padding-right:1em;")
Industrial Land Type
(-Inf,5] (5,30] (30,100] (100,500] (500,5000] (5000,20000] (20000, Inf]
LSIS 1235 4981 4482 5615 3576 327 48
NAL 2755 16870 9381 9328 6559 674 149
SIL 2042 9432 7594 10001 7705 1005 247
Total 6032 31283 21457 24944 17840 2006 444
Industrial Land Type
(0,2762] (2762,13001] (13001,38525] (38525,100191] (100191,217698] (217698,359925] (359925,814508]
LSIS 19489 679 81 12 3 0 0
NAL 43959 1490 215 40 6 1 1
SIL 35663 1938 316 81 21 3 3
Total 99111 4107 612 133 30 4 4
# "URSID" = ' ' (N=26,876 obs.) 
# read from Statistical Summary for 'Shape_Area' in QGIS
#noCode <- read.clipboard(header = TRUE)
noCode1 <- noCode
htmlTable(noCode1, rnames=F, caption="'Shape_Area' empty URSID", col.columns = c("none", "#F7F7F7"), css.cell="padding-left:1em; padding-right:1em;")
'Shape_Area' empty URSID
Statistic Value
Count 26872
Sum 1.16382e+7
Mean 433.098
Median 33.3326
St dev
(pop) 2890.51
St dev
(sample) 2890.56
Minimum 0.000824
Maximum 320419
Range 320419
Minority 0.000824
Majority 8.3886
Variety 26859
Q1 16.6567
Q3 202.166
IQR 185.509
Missing (null)
values 0

Sample of “URSID” = ‘’ (N=26,876 obs.) by ‘TYPE_2015’

26,640 obs. (out of N=26,876 obs.) are ‘NAL’ ‘TYPE_2015’ (see AECOM map for meaning of NAL - might be Non-designated Sites which although are part of the ‘GLA-Desiganted Industrial Land’ dataset). The absence of ‘URSID’ code might be related to being ‘Non-designated Sites’. However, there’re ‘big’ sites of ‘LSIS’ and ‘SIL’ type without URSID code. Also, there might be uncoded ‘NAL’ type areas that have the potential of being classified as ‘LSIS’ or ‘SIL’. The size of the area might be a factor to consider.
How is the size of the uncoded sites distributed according to ‘TYPE_2015’?

# subset URSID = ''
noURSID <- subset(ilddf, is.na(URSID))
noURSID <- noURSID[,c(8,15)]
noUT <- t(sapply(
  by(
    noURSID$Shape_Area, list(noURSID$TYPE_2015), cut, dig.lab=10,breaks=c(-Inf,5,30,100,500,5000,20000,Inf)),
  table))
noUT
     (-Inf,5] (5,30] (30,100] (100,500] (500,5000] (5000,20000] (20000, Inf]
LSIS       10     20       29        57        121           22            9
NAL       942  11740     5296      4547       3647          239           29
SIL        18     33       20        24         36           25            8
LS0tCnRpdGxlOiAiTWFudWZhY3R1cmluZyBwbGFjZXMgaW4gTG9uZG9uIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzMnCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiBubwotLS0KPHN0eWxlPgoqIHsKICBmb250LWZhbWlseTogIlBhbGF0aW5vIgp9CgpoMXsKICAgIGZvbnQtc2l6ZTogMTkwJQp9CgpoMnsKICAgIGZvbnQtc2l6ZTogMTYwJQp9CgpoM3sKICAgIGZvbnQtc2l6ZTogMTUwJQp9CgpoNHsKICAgIGZvbnQtc2l6ZTogMTMwJQp9CgpoNXsKICAgIGZvbnQtc2l6ZTogMTEwJQp9CgpoNnsKICAgIGZvbnQtc2l6ZTogOTAlCn0KdGFibGUgewogIHdpZHRoOiAxMDAlOwp9Cjwvc3R5bGU+CgoqbGlicmFyaWVzKgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShrbml0cikKbGlicmFyeShodG1sVGFibGUpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoc3ApCmxpYnJhcnkocmdlb3MpCmxpYnJhcnkodG1hcCkKbGlicmFyeSh0bWFwdG9vbHMpCmxpYnJhcnkoc2YpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoZ2VvanNvbmlvKQpsaWJyYXJ5KHNwRGF0YSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobWFwdG9vbHMpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHBseXIpCiNpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlIikKbGlicmFyeShyZXNoYXBlKQpsaWJyYXJ5KGNsYXNzSW50KQojaW5zdGFsbC5wYWNrYWdlcygiQkFNTXRvb2xzIikKbGlicmFyeShCQU1NdG9vbHMpCiNpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkoZGF0YS50YWJsZSkKYGBgCgojIFByb2JsZW0KSWRlbnRpZnkgbG9jYXRpb25zIG91dHNpZGUgdGhlIEluZHVzdHJpYWwgTGFuZCBEZXNpZ25hdGlvbiBhcmVhcyB3aXRoIGhpZ2ggY29uY2VudHJhdGlvbiBvZiBtYW51ZmFjdHVyaW5nLCBvdGhlciBlY29ub21pYyBhY3Rpdml0aWVzIGFuZCByZXNpZGVuY2VzLgoKIyBDb250ZXh0CgpXZSBoYXZlIGFuYWx5c2VkIDMgb3BlbiBkYXRhIGRhdGFzZXRzIHJlZmVyaW5nIHRvIE1hbnVmYWN0dXJpbmcgaW4gTG9uZG9uLiAgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpOYW1lIDwtIGMoJ0RpcmVjdG9yeSBvZiBMb25kb24gQnVzaW5lc3NlcyAtIFVLIFN0YW5kYXJkIEluZHVzdHJpYWwgQ2xhc3NpZmljYXRpb24gKFNJQyknLCdCdXNpbmVzcyBSZWdpc3RlciBhbmQgRW1wbG95bWVudCBTdXJ2ZXkgLSBCUkVTJywnSW50ZXIgRGVwYXJ0bWVudGFsIEJ1c2luZXNzIFJlZ2lzdGVyIChJREJSKScpClNvdXJjZSA8LSBjKCdMb25kb24gRGF0YSBTdG9yZSAoMSknLCdOT01JUyAtIE9mZmljaWFsIExhYm91ciBNYXJrZXQgU3RhdGlzdGljcyBPTlMgKDIpJywnTk9NSVMgLSBPZmZpY2lhbCBMYWJvdXIgTWFya2V0IFN0YXRpc3RpY3MgT05TJykKT2JzZXJ2YXRpb24gPC0gYygn4oCcRGF0YSBzbmFwc2hvdCBjb250YWluaW5nIGJhc2ljIGNvbXBhbnkgZGF0YSBvZiBsaXZlIGNvbXBhbmllcyBvbiB0aGUgcmVnaXN0ZXIuIEVhY2ggZW50cnkgcmVwcmVzZW50cyBhIGZpbmFuY2lhbCBhY2NvdW50cyBzdWJtaXNzaW9uIG9mIGVpdGhlciBhIHdob2xlIGNvbXBhbnkgb3IgcGFydCBvZiBvbmUuIFNvbWUgYnVzaW5lc3NlcyBoYXZlIG1vcmUgdGhhbiBvbmUgZW50cnkgaW4gdGhlIGRpcmVjdG9yeSBiZWNhdXNlIHRoZXkgbmVlZCB0byBzdWJtaXQgbW9yZSB0aGFuIG9uZSBzZXQgb2YgYWNjb3VudHMgZm9yIGRpZmZlcmVudCBwYXJ0cyBvZiB0aGVpciBidXNpbmVzcy7igJ0g4oCcVGhlIExvbmRvbiBjdXQgYXZhaWxhYmxlIHRvIGRvd25sb2FkIGhlcmUsIHdhcyBjcmVhdGVkIHVzaW5nIGEgcG9zdGNvZGUgbGlzdOKApiBpbmFjY3VyYWNpZXMgaW4gcG9zdGNvZGVzIG1heSBtZWFuIHRoYXQgbm8gbG9jYWwgYXV0aG9yaXR5IGlzIGxpc3RlZCBmb3IgYSBjb21wYW55LuKAnScsJ+KAnEFuIGVtcGxveWVyIHN1cnZleSBvZiB0aGUgbnVtYmVyIG9mIGpvYnMgaGVsZCBieSBlbXBsb3llZXMgYnJva2VuIGRvd24gYnkgZnVsbC9wYXJ0LXRpbWUgYW5kIGRldGFpbGVkIGluZHVzdHJ5ICg1IGRpZ2l0IFNJQzIwMDcp4oCdJywn4oCcQW4gZXh0cmFjdCByZWNvcmRpbmcgdGhlIG51bWJlciBvZiBsb2NhbCB1bml0cyB0aGF0IHdlcmUgbGl2ZSBhdCBhIHJlZmVyZW5jZSBkYXRlIGluIE1hcmNoLiBFc3RpbWF0ZXMgY2FuIGJlIGJyb2tlbiBkb3duIGJ5IGVtcGxveW1lbnQgc2l6ZSBiYW5kLCBkZXRhaWxlZCBpbmR1c3RyeSAoNSBkaWdpdCBTSUMyMDA3KSBhbmQgbGVnYWwgc3RhdHVzLuKAnSAtIOKAnEEgbG9jYWwgdW5pdCBpcyBhbiBpbmRpdmlkdWFsIHNpdGUgKGZvciBleGFtcGxlIGEgZmFjdG9yeSBvciBzaG9wKSBhc3NvY2lhdGVkIHdpdGggYW4gZW50ZXJwcmlzZS4gSXQgY2FuIGFsc28gYmUgcmVmZXJyZWQgdG8gYXMgYSB3b3JrcGxhY2Uu4oCdJykKR2VuZXJhbF9EZXNjIDwtIGMoJ1BvaW50IGRhdGEsIE4gPSAxLDEzMCw0NzQgb2JzLicsJ0VzdGltYXRlZCBudW1iZXIgb2Ygam9icyBwZXIgTFNPQSAoTiA9IDQsODM1IG9icy4pIEluY2x1ZGVzIEluZHVzdHJ5IHBlcmNlbnRhZ2UgKHBlcmNlbnRhZ2Ugb2Ygam9icyBpbiBNYW51ZmFjdHVyaW5nKSAoMyknLCdOdW1iZXIgb2Ygd29ya3BsYWNlcyBwZXIgTVNPQSAoTiA9IDk4MyBvYnMuKSAoNCknKQpWZXJzaW9uIDwtIGMoJ01heSAyMDE4JywnMjAxNyAobGF0ZXN0IGRhdGEpJywnMjAxOCAobGF0ZXN0IGRhdGEpJykKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpzVCA8LSBkYXRhLmZyYW1lKE5hbWUsIFNvdXJjZSwgT2JzZXJ2YXRpb24sIEdlbmVyYWxfRGVzYywgVmVyc2lvbikKaHRtbFRhYmxlKHNULCBybmFtZXM9RiwgYWxpZ249ImwiLCBjb2wuY29sdW1ucyA9IGMoIm5vbmUiLCAiI0Y3RjdGNyIpLCBjc3MuY2VsbD0icGFkZGluZzoxZW0iKQpgYGAKClVSTHM6ICAKMSBodHRwczovL2RhdGEubG9uZG9uLmdvdi51ayAgIAoyIGh0dHBzOi8vd3d3Lm5vbWlzd2ViLmNvLnVrLyAgCjMgaHR0cHM6Ly93d3cub25zLmdvdi51ay9lbXBsb3ltZW50YW5kbGFib3VybWFya2V0L3Blb3BsZWlud29yay9lbXBsb3ltZW50YW5kZW1wbG95ZWV0eXBlcy9idWxsZXRpbnMvYnVzaW5lc3NyZWdpc3RlcmFuZGVtcGxveW1lbnRzdXJ2ZXlicmVzcHJvdmlzaW9uYWxyZXN1bHRzL3Byb3Zpc2lvbmFscmVzdWx0czIwMTdyZXZpc2VkcmVzdWx0czIwMTYjcXVhbGl0eS1hbmQtbWV0aG9kb2xvZ3kgIAo0IGh0dHBzOi8vd3d3Lm9ucy5nb3YudWsvYWJvdXR1cy93aGF0d2Vkby9wYWlkc2VydmljZXMvaW50ZXJkZXBhcnRtZW50YWxidXNpbmVzc3JlZ2lzdGVyaWRiciBodHRwczovL3d3dy5vbnMuZ292LnVrL2J1c2luZXNzaW5kdXN0cnlhbmR0cmFkZS9idXNpbmVzcy9hY3Rpdml0eXNpemVhbmRsb2NhdGlvbi9tZXRob2RvbG9naWVzL3VrYnVzaW5lc3NhY3Rpdml0eXNpemVhbmRsb2NhdGlvbnFtaSAgCgojIENhcnRvZ3JhcGhpYyBzdW1tYXJ5CgoKCiMgQW5hbHlzaXMKCkEgZGV0YWlsZWQgYW5hbHlzaXMgd2FzIGNhcnJpZWQgb3V0IGZvciB0aGUgQlJFUyBkYXRhc2V0IGR1ZSB0byBmb3VyIHJlYXNvbnM6ICAKCjEuIFRoZSBudW1iZXIgb2YgbWFudWZhY3R1cmluZyBqb2JzIG9idGFpbmVkIGZyb20gdGhlIEJSRVMgZGF0YXNldCBpcyBjb25zaWRlcmVkIHRoZSBiZXN0IHByb3h5IHRvIHJlcHJlc2VudCBtYW51ZmFjdHVyaW5nIGludGVuc2l0eS4gVGhpcyBtZWFzdXJlIGNhbiBiZSBpbnRlcnByZXRlZCBhcyBhIGNvbWJpbmF0aW9uIG9mIG51bWJlciBvZiBtYW51ZmFjdHVyaW5nIHVuaXRzIGFuZCBzaXplLiAgCgoyLiBUaGUgbGV2ZWwgb2YgZGV0YWlsIG9mIHRoZSBCUkVTIGRhdGFzZXQgYXQgdGhlIExTT0EgYXJlYSBpcyBjb25zaWRlcmVkIHN1ZmZpY2llbnQgdG8gYWxsb3cgdGhlIHNlbGVjdGlvbiBvZiBjYXNlIHN0dWR5IGFyZWFzIGZvciBtaWNyby1tb3JwaG9sb2d5IGFuYWx5c2lzLiAgCgozLiBUaGUgU0lDIGRhdGFzZXQgZGVzcGl0ZSBoYXZpbmcgYSBmaW5lci1ncmFpbiByZXNvbHV0aW9uIGhhcyBzaG93biBpbm5hY3VyYWNpZXMgaW4gdGhlIGxvY2F0aW9uIG9mIHRoZSBkYXRhIHBvaW50cyAocmVmZXJlbmNlOiBWeW5lciBzdHJlZXQgY2FzZSBzdHVkeSBDaXRlcyBvZiBNYWtpbmcgcHJvamVjdCkuICAKCjQuIERlc3BpdGUgdGhlIGZhY3QgdGhhdCB0aGUgSURCUiBjb25zaWRlcnMgYSBsYXJnZXIgc2FtcGxlIGF0IHRoZSBuYXRpb25hbCBsZXZlbCwgaXQgaXMgYWdncmVnYXRlZCBhdCBhIGxvd2VyIHJlc29sdXRpb24gZ2VvZ3JhcGhpYyBhcmVhIChNU09BKS4gQWxzbywgYmVjYXVzZSBhY2NvcmRpbmcgdG8gYSBkYXRhIG1ldGhvZG9sb2dpY2FsIG5vdGUgIml0IGlzIHBvc3NpYmxlIHRvIGdldCBtdWx0aXBsZSBidXNpbmVzcyByZWdpc3RyYXRpb25zIGF0IGEgc2luZ2xlIGFkZHJlc3MgYW5kIHRoaXMgY2FuIGRpc3RvcnQgZGF0YSBmb3Igc21hbGxlciBnZW9ncmFwaGljYWwgYXJlYXMiIChodHRwczovL3d3dy5vbnMuZ292LnVrL2J1c2luZXNzaW5kdXN0cnlhbmR0cmFkZS9idXNpbmVzcy9hY3Rpdml0eXNpemVhbmRsb2NhdGlvbi9tZXRob2RvbG9naWVzL3VrYnVzaW5lc3NhY3Rpdml0eXNpemVhbmRsb2NhdGlvbnFtaS9wZGYpLiAgCgojIyBNZXRhZGF0YQpEYXRhIHNvdXJjZTogTk9NSVMgb2ZmaWNpYWwgbGFib3VyIG1hcmtldCBzdGF0aXN0aWNzIChPTlMpClVSTDogaHR0cHM6Ly93d3cubm9taXN3ZWIuY28udWsvICAKRGVmaW5pdGlvbjogKiJBbiBlbXBsb3llciBzdXJ2ZXkgb2YgdGhlIG51bWJlciBvZiBqb2JzIGhlbGQgYnkgZW1wbG95ZWVzIGJyb2tlbiBkb3duIGJ5IGZ1bGwvcGFydC10aW1lIGFuZCBkZXRhaWxlZCBpbmR1c3RyeSAoNSBkaWdpdCBTSUMyMDA3KS4gVGhlIHN1cnZleSByZWNvcmRzIGEgam9iIGF0IHRoZSBsb2NhdGlvbiBvZiBhbiBlbXBsb3llZXMgd29ya3BsYWNlLiBBdmFpbGFibGUgZnJvbSBjb3VudHJ5IGRvd24gdG8gbG93ZXIgbGV2ZWwgc3VwZXIgb3V0cHV0IGFyZWEgYW5kIFNjb3R0aXNoIGRhdGF6b25lLiIqICAKUmVmIFVSTHM6IGh0dHBzOi8vb25zZGlnaXRhbC5naXRodWIuaW8vZHAtY2xhc3NpZmljYXRpb24tdG9vbHMvc3RhbmRhcmQtaW5kdXN0cmlhbC1jbGFzc2lmaWNhdGlvbi9PTlNfU0lDX2hpZXJhcmNoeV92aWV3Lmh0bWwgIAoKUmVhZCBOT01JUyBkYXRhLiBMb3dlciBMYXllciBTdXBlciBPdXRwdXQgQXJlYSAoMjAxMSkgIApJbmR1c3RyeSBTdGFuZGFyZCBpbmR1c3RyaWFsIGNsYXNzaWZpY2F0aW9uIG9mIGVjb25vbWljIGFjdGl2aXRpZXMgKFNJQykgMjAwNyBzZWN0aW9uIEM6IE1hbnVmYWN0dXJpbmcKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kbm9tIDwtIHJlYWRfY3N2KCIvVm9sdW1lcy9yaXRkLWFnLXByb2plY3QtcmQwMGxxLWphbWZlODcvR0lTX0FuYWx5c2lzL2RhdGFQcm9jZXNzZWQvbm9taXNfNDgzNS5jc3YiKSAjIDQsODM1IG9icy4KYGBgCgojIyBEYXRhIHN1bW1hcnkKQ3JlYXRlIHZhcmlhYmxlICdsc29hMTFfY2QnIGZyb20gdmFyaWFibGUgJ2xzb2ExMV8yMDExJyBzdWJzdHJhY3QgY2hyIDEgdG8gNCAoZmlyc3QgNCBjaGFyYWN0ZXJzKQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kbm9tIDwtIG11dGF0ZShub20sIGxzb2ExMV9jZCA9IHN1YnN0cihsc29hXzIwMTEsIDEsIDkpKQpgYGAKClN1bW1hcnkgb2YgJ25vbScgQ291bnQgYW5kIEluZHVzdHJ5IHBlcmNlbnRhZ2UKYGBge3J9CnN1bW1hcnkobm9tKQpgYGAKCmBgYHtyfQpucm93KHRhYmxlKG5vbSRDb3VudCkpICMgWzFdIDM0CmRDb3VudCA8LWFzLmRhdGEuZnJhbWUodGFibGUobm9tJENvdW50KSkKY29sbmFtZXMoZENvdW50KSA8LWMoIkpvYnMiLCAiRnJlcXVlbmN5IikKZENvdW50MSA8LSBjYmluZChkQ291bnRbMToxMCwgXSwgZENvdW50WzExOjIwLCBdLCBkQ291bnRbMjE6MzAsIF0sIGRDb3VudFszMTo0MCwgXSkKaHRtbFRhYmxlKGRDb3VudDEsIHJuYW1lcz1GLCBjYXB0aW9uPSJKb2JzIGNvdW50IGZyZXF1ZW5jeSBwZXIgTFNPQSAoTiA9IDQsODM1KSIsIGNvbC5jb2x1bW5zID0gYygibm9uZSIsICIjRjdGN0Y3IiksIGNzcy5jZWxsPSJwYWRkaW5nLWxlZnQ6MWVtOyBwYWRkaW5nLXJpZ2h0OjFlbTsiKQpgYGAKTW9zdCBMU09BcyBoYXZlIDAgam9icyBpbiBtYW51ZmFjdHVyaW5nLiBBbW9uZyB0aGUgcmVzdCB0aGUgbW9zdCBmcmVxdWVudCBudW1iZXIgaXMgMTAgam9icyAoaW4gNTM5IExTT0FzKS4gSGlnaCBudW1iZXIgb2Ygam9icyAoID4gMTUwMCkgYXJlIGFuIGV4Y2VwdGlvbi4gCgpgYGB7cn0KdGFibGUobm9tWywzXSkgIyAyMiBMU09BIHdpdGggMjAlIGpvYnMgaW4gTWFudWZhY3R1cmluZyBJbmR1c3RyeQpgYGAKCmBgYHtyfQpucm93KHRhYmxlKG5vbSRgSW5kdXN0cnkgcGVyY2VudGFnZWApKSAjIFsxXSAxMDcKZEluZCA8LWFzLmRhdGEuZnJhbWUodGFibGUobm9tJGBJbmR1c3RyeSBwZXJjZW50YWdlYCkpCmNvbG5hbWVzKGRJbmQpIDwtYygiUGVyYy4iLCAiRnJlcXVlbmN5IikKZEluZDEgPC0gY2JpbmQoZEluZFsxOjIyLCBdLCBkSW5kWzIzOjQ0LCBdLCBkSW5kWzQ1OjY2LCBdLCBkSW5kWzY3Ojg4LCBdLCBkSW5kWzg5OjExMCwgXSkKaHRtbFRhYmxlKGRJbmQxLCBybmFtZXM9RiwgY2FwdGlvbj0iSm9icyBQZXJjZW50YWdlIGZyZXF1ZW5jeSBwZXIgTFNPQSAoTiA9IDQsODM1KSIsIGNvbC5jb2x1bW5zID0gYygibm9uZSIsICIjRjdGN0Y3IiksIGNzcy5jZWxsPSJwYWRkaW5nLWxlZnQ6MWVtOyBwYWRkaW5nLXJpZ2h0OjFlbTsiKQpgYGAKTW9zdCBMU09BcyBoYXZlIDAlIGpvYnMgaW4gbWFudWZhY3R1cmluZy4gQW1vbmcgdGhlIHJlc3QgdGhlIG1vc3QgZnJlcXVlbnQgcGVyY2VudGFnZSBpcyA1JSAoaW4gMTAyIExTT0FzKS4gSGlnaCBwZXJjZW50YWdlIG9mIGpvYnMgKCA+IDUzJSkgYXJlIGFuIGV4Y2VwdGlvbi4KCiMjIEhpc3RvZ3JhbXMKYGBge3J9CiMgZHJvcCAwIHZhbHVlcwpub20xIDwtIHN1YnNldChub20sIG5vbSRDb3VudCA+IDAgJiBub20kYEluZHVzdHJ5IHBlcmNlbnRhZ2VgID4gMCkgIyAxNzMwCmBgYAoKU3VtbWFyeSBvZiB2YWx1ZXMgPiAwICAKYGBge3J9CnN1bW1hcnkobm9tMSkKYGBgCgpgYGB7cn0KIyBzdHlsZQp0aCA8LSB0aGVtZV90dWZ0ZShiYXNlX2ZhbWlseSA9ICJHZW9yZ2lhIikKCmgxIDwtIGdncGxvdChub20xLCBhZXMoQ291bnQpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSA2MDAwLzUsIGZpbGw9Im1hZ2VudGEiKSArIHRoICsgeWxhYigiTFNPQXMiKSArIHhsYWIoIkpvYnMgY291bnQiKQpoMiA8LSBnZ3Bsb3Qobm9tMSwgYWVzKENvdW50KSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUwLzUsIGZpbGw9Im1hZ2VudGEiKSArIHRoICsgeGxpbShjKDAsIDE1MCkpICsgeWxhYigiTFNPQXMiKSArIHhsYWIoIkpvYnMgY291bnQgKDAtMTUwKSIpCmgzIDwtIGdncGxvdChub20xLCBhZXMoYEluZHVzdHJ5IHBlcmNlbnRhZ2VgKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsPSJtYWdlbnRhIikgKyB0aCArIHlsYWIoIkxTT0FzIikgKyB4bGFiKCIlIG9mIGpvYnMgaW4gTWFudWZhY3R1cmluZyIpCmg0IDwtIGdncGxvdChub20xLCBhZXMoYEluZHVzdHJ5IHBlcmNlbnRhZ2VgKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAwLCBmaWxsPSJtYWdlbnRhIikgKyB0aCArIHhsaW0oYygwLCAzNSkpICsgeWxhYigiTFNPQXMiKSArIHhsYWIoIiUgb2Ygam9icyBpbiBNYW51ZmFjdHVyaW5nICgwLTM1JSkiKQpncmlkLmFycmFuZ2UoaDEsIGgyLCBoMywgaDQsIG5yb3c9MikKYGBgCgojIyBCb3hwb2xvdHMKYGBge3J9CmZuQyA8LSBmaXZlbnVtKG5vbTEkQ291bnQpCmZuUCA8LSBmaXZlbnVtKG5vbTEkYEluZHVzdHJ5IHBlcmNlbnRhZ2VgKQpgYGAKCmBgYHtyfQphbkMgPC0gYW5ub3RhdGUoZ2VvbT0idGV4dCIsIGxhYmVsPXJvdW5kKGZuQyAsZGlnaXRzPTIpLCB4PSAxLCB5PWZuQywgc2l6ZSA9IDMsIGZhbWlseSA9ICJHZW9yZ2lhIiwgaGp1c3QgPS0uMikKYW5QIDwtIGFubm90YXRlKGdlb209InRleHQiLCBsYWJlbD1yb3VuZChmblAgLGRpZ2l0cz0yKSwgeD0gMSwgeT1mblAsIHNpemUgPSAzLCBmYW1pbHkgPSAiR2VvcmdpYSIsIGhqdXN0ID0tLjIpCnRoIDwtIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpLGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKQoKYkMgPC0gZ2dwbG90KG5vbTEsIGFlcygxLCBDb3VudCkpICsgZ2VvbV90dWZ0ZWJveHBsb3QoKSArIHNjYWxlX3lfbG9nMTAoKSArIHRoZW1lX2NsYXNzaWMoKSArIGFuQyArCiAgZ2d0aXRsZSgiSm9icyBDb3VudCAoTiA9IDEsNzMwKSIpICsgdGggKyB0aGVtZV90dWZ0ZSgpCmJQIDwtIGdncGxvdChub20xLCBhZXMoMSwgYEluZHVzdHJ5IHBlcmNlbnRhZ2VgKSkgKyBnZW9tX3R1ZnRlYm94cGxvdCgpICsgc2NhbGVfeV9sb2cxMCgpICsgdGhlbWVfY2xhc3NpYygpICsgYW5QICArIGdndGl0bGUoIkpvYnMgUGVyY2VudGFnZSAoTiA9IDEsNzMwKSIpICsgdGggKyB0aGVtZV90dWZ0ZSgpCgpncmlkLmFycmFuZ2UoYkMsIGJQLCBucm93PTEpCmBgYAoKIyMgTWFwcwpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbHNvYSA8LSBzdF9yZWFkKCIvVm9sdW1lcy9yaXRkLWFnLXByb2plY3QtcmQwMGxxLWphbWZlODcvR0lTX0FuYWx5c2lzL2RhdGFSYXcvc3RhdGlzdGljYWwtZ2lzLWJvdW5kYXJpZXMtbG9uZG9uL0VTUkkvTFNPQV8yMDExX0xvbmRvbl9nZW5fTUhXLnNocCIpCmBgYAoKQ3JlYXRlIGdyYXkgTG9uZG9uIGJhc2VtYXAKYGBge3IgZWNobz1GQUxTRX0KZ0xvbiA8LSBzdF9yZWFkKCIvVm9sdW1lcy9yaXRkLWFnLXByb2plY3QtcmQwMGxxLWphbWZlODcvR0lTX0FuYWx5c2lzL2RhdGFSYXcvc3RhdGlzdGljYWwtZ2lzLWJvdW5kYXJpZXMtbG9uZG9uL0VTUkkvTVNPQV8yMDExX0xvbmRvbl9nZW5fTUhXLnNocCIpCmdMb25DIDwtc3RfY29tYmluZShnTG9uKQpxdG0oZ0xvbkMsIGZpbGwgPSAiZ3JleTkwIiwgYm9yZGVycyA9IE5VTEwpCmBgYAoKSm9pbiB3aXRoIE5PTUlTIGRhdGEgJ25vbScKYGBge3J9Cm1wbCA8LSBhcHBlbmRfZGF0YShsc29hLCBub20sIGtleS5zaHAgPSAiTFNPQTExQ0QiLCBrZXkuZGF0YSA9ICJsc29hMTFfY2QiLCBpZ25vcmUuZHVwbGljYXRlcyA9IFRSVUUsIGlnbm9yZS5uYSA9IFRSVUUpCm5hbWVzKG1wbCkKYGBgCgpNYXBzIG9mIGpvYiBDb3VudHMgPiA0MCBhbmQgUGVyY2VudGFnZSA+IDYlICg+IDNyZCBRKQpgYGB7cn0KIyBjaGFuZ2UgY29sdW1uIG5hbWUKY29sbmFtZXMobXBsKVsxN10gPC0gIkluZFBlciIKCmM0MCA8LSBzdWJzZXQobXBsLCBDb3VudCA+PSA0MCkgIyA0Mzkgb2JzLgpwNiA8LSBzdWJzZXQobXBsLCBJbmRQZXIgPj0gNikgIyA0MzQgb2JzLgojIENQIDwtIHN1YnNldChtcGwsIENvdW50ID49IDQwIHwgSW5kUGVyID49IDYpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIGRwaT0zMDAsIG91dC53aWR0aD0iMjAwMHB4In0KbWM0MCA8LSB0bV9zaGFwZShnTG9uQykgKwogIHRtX2ZpbGwoY29sID0gImdyYXk5NSIpICsKICB0bV9zaGFwZShjNDApICsKICAgIHRtX3BvbHlnb25zKCJDb3VudCIsIAogICAgICAgIHN0eWxlPSJqZW5rcyIsCiAgICAgICAgcGFsZXR0ZT0iUHVSZCIsCiAgICAgICAgdGl0bGU9ICJDb3VudCIsCiAgICAgICAgYm9yZGVyLmNvbD0id2hpdGUiLAogICAgICAgIGJvcmRlci5hbHBoYSA9IDAuMSwKICAgICAgICBsZWdlbmQuaGlzdCA9IFQpICsKICB0bV9sYXlvdXQoaW5uZXIubWFyZ2lucyA9IGMoMCwgMC4xLCAwLjA1LCAwLjIpLCBmcmFtZSA9IEYsIAogICAgICAgICAgICBsZWdlbmQub3V0c2lkZSA9IFQsIGxlZ2VuZC5vdXRzaWRlLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5zdGFjayA9ICJob3Jpem9udGFsIiwgbGVnZW5kLmhpc3Qud2lkdGggPSAzLCBsZWdlbmQuaGlzdC5oZWlnaHQgPSAwLjgpICsKICB0bV9sZWdlbmQobWFpbi50aXRsZSA9ICJKb2JzIENvdW50ID4gM3JkIFEgKE49NDM5IG9icy4pIiwKICAgICAgICAgIG1haW4udGl0bGUucG9zaXRpb24gPSAibGVmdCIsCiAgICAgICAgICBtYWluLnRpdGxlLnNpemU9MC45KQptYzQwCmBgYAoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NiwgZHBpPTMwMCwgb3V0LndpZHRoPSIyMDAwcHgifQptcDYgPC0gdG1fc2hhcGUoZ0xvbkMpICsKICB0bV9maWxsKGNvbCA9ICJncmF5OTUiKSArIAogIHRtX3NoYXBlKHA2KSArCiAgICB0bV9wb2x5Z29ucygiSW5kUGVyIiwgCiAgICAgICAgc3R5bGU9ImplbmtzIiwKICAgICAgICBwYWxldHRlPSJCdVB1IiwKICAgICAgICB0aXRsZT0gIlBlcmNlbnRhZ2UiLAogICAgICAgIGJvcmRlci5jb2w9IndoaXRlIiwKICAgICAgICBib3JkZXIuYWxwaGEgPSAwLjEsCiAgICAgICAgbGVnZW5kLmhpc3QgPSBUKSArCiAgdG1fbGF5b3V0KGlubmVyLm1hcmdpbnMgPSBjKDAsIDAuMSwgMC4wNSwgMC4yKSwgZnJhbWUgPSBGLCAKICAgICAgICAgICAgbGVnZW5kLm91dHNpZGUgPSBULCBsZWdlbmQub3V0c2lkZS5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuc3RhY2sgPSAiaG9yaXpvbnRhbCIsIGxlZ2VuZC5oaXN0LndpZHRoID0gMywgbGVnZW5kLmhpc3QuaGVpZ2h0ID0gMC44KSArCiAgdG1fbGVnZW5kKG1haW4udGl0bGUgPSAiSm9icyBQZXJjZW50YWdlID4gM3JkIFEgKE49NDM0IG9icy4pIiwKICAgICAgICAgIG1haW4udGl0bGUucG9zaXRpb24gPSAibGVmdCIsCiAgICAgICAgICBtYWluLnRpdGxlLnNpemU9MC45KQptcDYKYGBgCgpgYGB7cn0KdG1hcF9hcnJhbmdlKG1jNDAgLG1wNiAsIG5yb3c9MSkKYGBgCkEgdmlzdWFsIGNvbXBhcmlzb24gc2hvd3MgdGhhdCBMU09BcyB3aXRoIGhpZ2ggbnVtYmVyIG9mIGpvYnMgaW4gc29tZSBjYXNlcyBpcyBjb2luY2lkZW50IHdpdGggTFNPQXMgd2l0aCBoaWdoIHBlcmNlbnRhZ2Ugb2Ygam9icy4gQm90aCBtZWF1cmVzIG1pZ2h0IGJlIGluZGljYXRvcnMgb2YgJ21hbnVmYWN0dXJpbmcgaW50ZW5zaXR5Jy4KCmBgYHtyfQptc3VtIDwtIHRtX3NoYXBlKG1wbCkgKwogIHRtX3BvbHlnb25zKGNvbD0iI2ZmZmZlNSIsIGJvcmRlci5jb2w9IiNlZGVkZWQiLCBib3JkZXIuYWxwaGEgPSAwLjAxKSArIAogIHRtX3NoYXBlKGM0MCkgKwogIHRtX3BvbHlnb25zKCJDb3VudCIsCiAgICAgICAgICAgICAgc3R5bGU9ImplbmtzIiwKICAgICAgICAgICAgICBwYWxldHRlPSJCdVB1IiwKICAgICAgICAgICAgICB0aXRsZT0iSm9icyBDb3VudCIsCiAgICAgICAgICAgICAgYm9yZGVyLmNvbD0id2hpdGUiLAogICAgICAgICAgICAgIGJvcmRlci5hbHBoYSA9IDAuMSwKICAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKyAKICB0bV9zaGFwZShwNikgKwogIHRtX3BvbHlnb25zKGJvcmRlci5jb2wgPSAibWFnZW50YSIsIAogICAgICAgICAgICAgIGJvcmRlci5hbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgYWxwaGEgPSAwLAogICAgICAgICAgICAgIHBvcHVwLnZhcnM9IGMoIkNvdW50IiAsIkluZFBlciIpKSArCiAgdG1fbGF5b3V0KGlubmVyLm1hcmdpbnMgPSBjKDAsIDAuMSwgMC4wNSwgMC4yKSwgZnJhbWUgPSBGKSAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgZHBpPTMwMCwgb3V0LndpZHRoPSIyMDAwcHgifQp0bWFwX21vZGUoInBsb3QiKQptc3VtCmBgYAoKSW50ZXJhY3RpdmUgTWFwCmBgYHtyfQojbXN1bS5pIDwtIG1zdW0KI3RtYXBfbW9kZSgidmlldyIpCiNtc3VtLmkKYGBgCgpgYGB7cn0KI3RtYXBfc2F2ZShtc3VtLmksICJtc3VtLmh0bWwiKQpgYGAKCgpUaGUgc2VsZWN0aW9uIG9mIHZhbHVlcyB3aXRoIGJvdGggY29uZGl0aW9ucyBDb3VudCA+PSA0MCAmIEluZFBlciA+PSA2IHNob3dzIDI1MyBvYnMuCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIGRwaT0zMDAsIG91dC53aWR0aD0iMjAwMHB4In0KQ1AgPC0gc3Vic2V0KG1wbCwgQ291bnQgPj0gNDAgJiBJbmRQZXIgPj0gNikgIyAyNTMgb2JzLgptQ1AgPC0gdG1fc2hhcGUoQ1ApICsKICAgIHRtX3BvbHlnb25zKGMoIkNvdW50IiwKICAgICAgICAgICAgICAgICAgIkluZFBlciIpLCAKICAgICAgICBzdHlsZT0iamVua3MiLAogICAgICAgIHBhbGV0dGU9bGlzdCgiUHVSZCIsIkJ1UHUiKSwKICAgICAgICB0aXRsZT1jKCJDb3VudCIsCiAgICAgICAgICAgICAgICAiUGVyY2VudGFnZSIpLAogICAgICAgIGJvcmRlci5jb2w9IndoaXRlIiwKICAgICAgICBib3JkZXIuYWxwaGEgPSAwLjEpICsKICB0bV9sYXlvdXQoaW5uZXIubWFyZ2lucyA9IGMoMCwgMC4xLCAwLjA1LCAwLjIpLCBmcmFtZSA9IEYpICsKICB0bV9sZWdlbmQobGVnZW5kLnBvc2l0aW9uID0gYygicmlnaHQiLCAiYm90dG9tIiksCiAgICAgICAgICBtYWluLnRpdGxlID0gIkpvYnMgYW5kIFBlcmNlbnRhZ2UgPiAzcmQgUSAoTj0yNTMgb2JzLikiLAogICAgICAgICAgbWFpbi50aXRsZS5wb3NpdGlvbiA9ICJjZW50ZXIiLAogICAgICAgICAgbWFpbi50aXRsZS5zaXplPTAuOSkKbUNQCmBgYAoKIyMjIEluZHVzdHJpYWwgTGFuZCAyMDE1CgpgYGB7cn0KaWxkIDwtIHN0X3JlYWQoIi9Wb2x1bWVzL3JpdGQtYWctcHJvamVjdC1yZDAwbHEtamFtZmU4Ny9HSVNfQW5hbHlzaXMvZGF0YVByb2Nlc3NlZC9HTEFfSW5kX0xhbmRfQmFzZWxpbmVfMjAxNS9HTEFfSW5kX0xhbmRfYmxfMjAxNS5zaHAiKQpgYGAKClN1bW1hcnkgb2YgJ2lsZCcgKG49MTA0MDA2IG9icy4pCmBgYHtyfQpzdW1tYXJ5KGlsZCkKYGBgCgpMYXJnZXN0IGFyZWEgaXMgbmVhciA4MSBoYSBhbmQgMXN0IFF1IGdvZXMgZnJvbSAwIHRvIDE4IHNxbS4gKHNxbSB0byBoYSA9IGRpdmlkZSBieSAxMGspCkZyZXF1ZW5jeSBieSB0eXBlICgnVFlQRV8yMDE1JykgIApgYGB7cn0KdDUgPC0gY291bnQoaWxkLCB2YXJzID0gIlRZUEVfMjAxNSIpCgpodG1sVGFibGUodDUsIHJuYW1lcz1GLCBjYXB0aW9uPSJJbmR1c3RyaWFsIExhbmQgVHlwZSIsIGNvbC5jb2x1bW5zID0gYygibm9uZSIsICIjRjdGN0Y3IiksIGNzcy5jZWxsPSJwYWRkaW5nLWxlZnQ6MWVtOyBwYWRkaW5nLXJpZ2h0OjFlbTsiKQpgYGAKClNoYXBlIGFyZWEgc3VtbWFyeSBieSBUeXBlCmBgYHtyfQpsaWJyYXJ5KHB1cnJyKQp0eXBlU1VNIDwtIGlsZCAlPiUgc3BsaXQoLiRUWVBFXzIwMTUpICU+JSBtYXAoc3VtbWFyeSkKYGBgCgpgYGB7cn0KY2xhc3MoaWxkKQppbGRkZiA8LSBzdF9zZXRfZ2VvbWV0cnkoaWxkLCBOVUxMKQoKYGBgCgpgYGB7cn0KdFN1IDwtIGlsZGRmWywgYyg4LDE1KV0gJT4lCiAgZ3JvdXBfYnkoVFlQRV8yMDE1KSAlPiUKICBzdW1tYXJpc2VfaWYoCiAgICBpcy5udW1lcmljLAogICAgZnVucyhtZWFuID0gbWVhbiwgbWVkaWFuID0gbWVkaWFuLCBtaW4gPSBtaW4sIG1heCA9IG1heCwgc2QgPSBzZCkgCiAgKQpgYGAKCmBgYHtyfQpyb3VuZF9kZiA8LSBmdW5jdGlvbih4LCBkaWdpdHMpIHsKICAgICMgcm91bmQgYWxsIG51bWVyaWMgdmFyaWFibGVzCiAgICAjIHg6IGRhdGEgZnJhbWUgCiAgICAjIGRpZ2l0czogbnVtYmVyIG9mIGRpZ2l0cyB0byByb3VuZAogICAgbnVtZXJpY19jb2x1bW5zIDwtIHNhcHBseSh4LCBtb2RlKSA9PSAnbnVtZXJpYycKICAgIHhbbnVtZXJpY19jb2x1bW5zXSA8LSAgcm91bmQoeFtudW1lcmljX2NvbHVtbnNdLCBkaWdpdHMpCiAgICB4Cn0KCnRTdSA8LSBjYmluZCh0U3VbLDFdLCByb3VuZF9kZih0U3VbLDI6NV0sIDIpKQpgYGAKCgpgYGB7cn0KaHRtbFRhYmxlKHRTdSwgcm5hbWVzPUYsIGNhcHRpb249IkluZHVzdHJpYWwgTGFuZCBUeXBlIiwgY29sLmNvbHVtbnMgPSBjKCJub25lIiwgIiNGN0Y3RjciKSwgY3NzLmNlbGw9InBhZGRpbmctbGVmdDoxZW07IHBhZGRpbmctcmlnaHQ6MWVtOyIpCmBgYAoKQW5hbHlzZSBhcmVhIGRpc3RyaWJ1dHVvbiBieSB0eXBlCmBgYHtyfQppbGRkZlQgPC0gaWxkZGZbLGMoOCwxNSldIAp0eVMgPC0gdChzYXBwbHkoCiAgYnkoCiAgICBpbGRkZlQkU2hhcGVfQXJlYSwgbGlzdChpbGRkZlQkVFlQRV8yMDE1KSwgY3V0LCBkaWcubGFiPTEwLGJyZWFrcz1jKC1JbmYsNSwzMCwxMDAsNTAwLDUwMDAsMjAwMDAsSW5mKSksCiAgdGFibGUpKQp0eVMgPC0gYXMuZGF0YS5mcmFtZSh0eVMpCiMgYWRkIHJvdyB3aXRoIFRvdGFscwp0eVMgPC0gcmJpbmQodHlTLCBjb2xTdW1zKHR5UykpCmF0dHIodHlTLCAicm93Lm5hbWVzIilbNF0gPC0gIlRvdGFsIgp0eVMKCmBgYAoKYGBge3J9Cmh0bWxUYWJsZSh0eVMsIGNhcHRpb249IkluZHVzdHJpYWwgTGFuZCBUeXBlIiwgY29sLmNvbHVtbnMgPSBjKCJub25lIiwgIiNGN0Y3RjciKSwgY3NzLmNlbGw9InBhZGRpbmctbGVmdDoxZW07IHBhZGRpbmctcmlnaHQ6MWVtOyIpCmBgYAoKCmBgYHtyfQojIGZhc3RlciBmdW5jdGlvbiB0aGFuIENsYXNzSW50IHRvIGNhbGN1bGF0ZSBjbGFzc2VzCmplbmtzNyA8LSBnZXRKZW5rc0JyZWFrcyhpbGRkZlQkU2hhcGVfQXJlYSwgOCkKCmplbmtzNyA8LSByb3VuZChqZW5rczcpCgp0eVMxIDwtIHQoc2FwcGx5KAogIGJ5KAogICAgaWxkZGZUJFNoYXBlX0FyZWEsIGxpc3QoaWxkZGZUJFRZUEVfMjAxNSksIGN1dCwgZGlnLmxhYj0xMCwgYnJlYWtzPWplbmtzNyksCiAgdGFibGUpKQp0eVMxIDwtIGFzLmRhdGEuZnJhbWUodHlTMSkKCiMgYWRkIHJvdyB3aXRoIFRvdGFscwp0eVMxIDwtIHJiaW5kKHR5UzEsIGNvbFN1bXModHlTMSkpCmF0dHIodHlTMSwgInJvdy5uYW1lcyIpWzRdIDwtICJUb3RhbCIKCmh0bWxUYWJsZSh0eVMxLCBjYXB0aW9uPSJJbmR1c3RyaWFsIExhbmQgVHlwZSIsIGNvbC5jb2x1bW5zID0gYygibm9uZSIsICIjRjdGN0Y3IiksIGNzcy5jZWxsPSJwYWRkaW5nLWxlZnQ6MWVtOyBwYWRkaW5nLXJpZ2h0OjFlbTsiKQpgYGAKCmBgYHtyfQojICJVUlNJRCIgPSAnICcgKE49MjYsODc2IG9icy4pIAojIHJlYWQgZnJvbSBTdGF0aXN0aWNhbCBTdW1tYXJ5IGZvciAnU2hhcGVfQXJlYScgaW4gUUdJUwoKbm9Db2RlIDwtIHJlYWQuY2xpcGJvYXJkKGhlYWRlciA9IFRSVUUpCm5vQ29kZTEgPC0gbm9Db2RlCmh0bWxUYWJsZShub0NvZGUxLCBybmFtZXM9RiwgY2FwdGlvbj0iJ1NoYXBlX0FyZWEnIGVtcHR5IFVSU0lEIiwgY29sLmNvbHVtbnMgPSBjKCJub25lIiwgIiNGN0Y3RjciKSwgY3NzLmNlbGw9InBhZGRpbmctbGVmdDoxZW07IHBhZGRpbmctcmlnaHQ6MWVtOyIpCgoKYGBgCgpTYW1wbGUgb2YgIlVSU0lEIiA9ICcgJyAoTj0yNiw4NzYgb2JzLikgYnkgJ1RZUEVfMjAxNScKYGBge3IsIG91dC53aWR0aCA9ICIxMDAwcHgiLCBlY2hvPUZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibm9Db2RlX0luZExhbmREZXMucG5nIikKYGBgCgoyNiw2NDAgb2JzLiAob3V0IG9mIE49MjYsODc2IG9icy4pIGFyZSAnTkFMJyAnVFlQRV8yMDE1JyAoc2VlIEFFQ09NIG1hcCBmb3IgbWVhbmluZyBvZiBOQUwgLSBtaWdodCBiZSBOb24tZGVzaWduYXRlZCBTaXRlcyB3aGljaCBhbHRob3VnaCBhcmUgcGFydCBvZiB0aGUgJ0dMQS1EZXNpZ2FudGVkIEluZHVzdHJpYWwgTGFuZCcgZGF0YXNldCkuIFRoZSBhYnNlbmNlIG9mICdVUlNJRCcgY29kZSBtaWdodCBiZSByZWxhdGVkIHRvIGJlaW5nICdOb24tZGVzaWduYXRlZCBTaXRlcycuIEhvd2V2ZXIsIHRoZXJlJ3JlICdiaWcnIHNpdGVzIG9mICdMU0lTJyBhbmQgJ1NJTCcgdHlwZSB3aXRob3V0IFVSU0lEIGNvZGUuIEFsc28sIHRoZXJlIG1pZ2h0IGJlIHVuY29kZWQgJ05BTCcgdHlwZSBhcmVhcyB0aGF0IGhhdmUgdGhlIHBvdGVudGlhbCBvZiBiZWluZyBjbGFzc2lmaWVkIGFzICdMU0lTJyBvciAnU0lMJy4gVGhlIHNpemUgb2YgdGhlIGFyZWEgbWlnaHQgYmUgYSBmYWN0b3IgdG8gY29uc2lkZXIuICAKSG93IGlzIHRoZSBzaXplIG9mIHRoZSB1bmNvZGVkIHNpdGVzIGRpc3RyaWJ1dGVkIGFjY29yZGluZyB0byAnVFlQRV8yMDE1Jz8KCmBgYHtyfQojIHN1YnNldCBVUlNJRCA9ICcnCm5vVVJTSUQgPC0gc3Vic2V0KGlsZGRmLCBpcy5uYShVUlNJRCkpCm5vVVJTSUQgPC0gbm9VUlNJRFssYyg4LDE1KV0Kbm9VVCA8LSB0KHNhcHBseSgKICBieSgKICAgIG5vVVJTSUQkU2hhcGVfQXJlYSwgbGlzdChub1VSU0lEJFRZUEVfMjAxNSksIGN1dCwgZGlnLmxhYj0xMCxicmVha3M9YygtSW5mLDUsMzAsMTAwLDUwMCw1MDAwLDIwMDAwLEluZikpLAogIHRhYmxlKSkKbm9VVAoKYGBgCgoKCgoK